package cn.flkj.lucia1a4a1.intermediate;

import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.xpath.internal.operations.Or;
import lombok.NonNull;
import org.hyperledger.fabric.protos.peer.Query;
import org.hyperledger.fabric.sdk.HFClient;
import org.hyperledger.fabric.sdk.Peer;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.exception.CryptoException;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.hyperledger.fabric.sdk.exception.TransactionException;
import org.hyperledger.fabric.sdk.helper.Utils;
import org.hyperledger.fabric.sdk.security.CryptoSuite;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Collection;

/**
 * @author : 州长在手 2021/1/14 上午11:43
 */
public class OrgManager {
    private final IntermediateOrg intermediateOrg;
    //  private final FabricStore fs = FabricStore.getInstance();

    public OrgManager(String orgMSPID, boolean openTLS) {
        intermediateOrg = new IntermediateOrg();
        intermediateOrg.setOrgMSPID(orgMSPID);
        intermediateOrg.openTLS(openTLS);
    }

    /**
     * 设置默认用户（一个特殊用户，即可对Channel及ChainCode进行操作的用户，一般为Admin，在有特殊操作需求的情况下，channelArtifactsPath不为null；
     * 也可以是一个已经在服务器生成好用户相关证书文件的用户，在没有特殊操作需求的情况下，一般channelArtifactsPath设置为null即可）
     *
     * @param userName        用户名
     * @param skPath          带有节点签名密钥的PEM文件——sk路径
     * @param certificatePath 带有节点的X.509证书的PEM文件——certificate路径
     * @return self
     */
    public OrgManager setUser(@Nonnull String leagueName,
                              @Nonnull String orgName,
                              @Nonnull String peerName,
                              @Nonnull String userName,
                              @Nonnull String skPath,
                              @Nonnull String certificatePath,
                              @NonNull String mspId) throws IOException {

        IntermediateUser user = new IntermediateUser(leagueName, orgName, peerName, userName, skPath, certificatePath, mspId);
        // 添加用于区别peer组织的标识
        intermediateOrg.setOrgName(orgName);
        intermediateOrg.addUser(user);
        intermediateOrg.setUsername(user.getKeyForFabricStoreName());
        return this;
    }

    public void addOrderer(String ordererName,
                           String ordererLocation,
                           String ordererServerCrtPath,
                           String ordererClientCertPath,
                           String ordererClientKeyPath) {
        intermediateOrg.addOrderer(ordererName, String.format("%s%s", "grpc://", ordererLocation), ordererServerCrtPath, ordererClientCertPath, ordererClientKeyPath);
    }

    public void addPeer(String peerName,
                        String peerLocation,
                        String peerEventHubLocation,
                        String peerServerCrtPath,
                        String peerClientCertPath,
                        String peerClientKeyPath) {
        intermediateOrg.addPeer(peerName, String.format("%s%s", "grpc://", peerLocation), String.format("%s%s", "grpc://", peerEventHubLocation), peerServerCrtPath, peerClientCertPath, peerClientKeyPath);
    }

    /**
     * 设置智能合约
     *
     * @param chaincodeName    智能合约名称
     * @param chaincodePath    智能合约路径
     * @param GOPATH           系统GOPATH路径
     * @param chaincodePolicy  智能合约背书文件路径
     * @param chaincodeVersion 智能合约版本
     * @param proposalWaitTime 单个提案请求的超时时间以毫秒为单位
     */
    public OrgManager addChainCode(String chaincodeName, String chaincodePath, String GOPATH, String chaincodePolicy, String chaincodeVersion, int proposalWaitTime) {
        IntermediateChaincodeID chaincode = new IntermediateChaincodeID();
        chaincode.setChaincodeName(chaincodeName);
        chaincode.setChaincodeSource(GOPATH);
        chaincode.setChaincodePath(chaincodePath);
        chaincode.setChaincodePolicy(chaincodePolicy);
        chaincode.setChaincodeVersion(chaincodeVersion);
        chaincode.setProposalWaitTime(proposalWaitTime);
        chaincode.setChaincodeID();
        intermediateOrg.addChaincode(chaincode);
        return this;
    }

    /**
     * 设置频道
     *
     * @param channelName 频道名称
     * @return Fabric
     */
    public OrgManager setChannel(String channelName) {
        IntermediateChannel channel = new IntermediateChannel();
        channel.setChannelName(channelName);
        intermediateOrg.setChannel(channel);
        return this;
    }

    public OrgManager start() throws IllegalAccessException, InvocationTargetException, InvalidArgumentException, InstantiationException, NoSuchMethodException, CryptoException, ClassNotFoundException, TransactionException {
        if (intermediateOrg.getPeers().size() == 0) {
            throw new RuntimeException("peers is null or peers size is 0");
        }
        if (intermediateOrg.getOrderers().size() == 0) {
            throw new RuntimeException("orderers is null or orderers size is 0");
        }
        /*if (orgMap.get(cc).getChainCodes().size() == 0) {
            throw new RuntimeException("chaincode must be instantiated");
        }*/

        // 根据TLS开启状态循环确认Peer节点各服务的请求grpc协议
        for (IntermediatePeer peer : intermediateOrg.getPeers()) {
            peer.setPeerLocation(this.grpcTLSify(intermediateOrg.openTLS(), peer.getPeerLocation()));
            //  peer.setPeerEventHubLocation(this.grpcTLSify(intermediateOrg.openTLS(),peer.getPeerEventHubLocation()));
        }
        // 根据TLS开启状态循环确认Orderer节点各服务的请求grpc协议
        for (IntermediateOrderer orderer : intermediateOrg.getOrderers()) {
            orderer.setOrdererLocation(grpcTLSify(intermediateOrg.openTLS(), orderer.getOrdererLocation()));
        }
        HFClient client = HFClient.createNewInstance();
        client.setCryptoSuite(CryptoSuite.Factory.getCryptoSuite());
        intermediateOrg.setClient(client);
        // 通过参数传递消除循环依赖
        intermediateOrg.getChannel().init(
                intermediateOrg.getUser(intermediateOrg.getUsername()),
                intermediateOrg.getOrderers(),
                intermediateOrg.getPeers(),
                intermediateOrg.openTLS()
        );
        intermediateOrg.getChannel().setChannel(intermediateOrg.getClient());
        return this;
    }

    private String grpcTLSify(boolean openTLS, String location) {
        location = location.trim();
        Exception e = Utils.checkGrpcUrl(location);
        if (e != null) {
            throw new RuntimeException(String.format("Bad TEST parameters for grpc url %s", location), e);
        }
        return openTLS ? location.replaceFirst("^grpc://", "grpcs://") : location;

    }
    //-----------------------安装链码-----------------------安装链码-----------------------安装链码-----------------------

    public JSONObject lifecycleChaincodeInstall(
            String chaincodeName,
            String chaincodeVersion,
            String chaincodeLabel, // 标签，是名字加版本号的结合
            String chaincodeSourceLocation, // GOPATH
            String chaincodePath, // 相对于GOPATH的路径
            String metadadataSource, // metadadataSource,一般是couchdb的连接方式JSON的路径
            String chaincodeEndorsementPolicyPath // 策略文件
    )  {
        String pkid = null;
        try {
        IntermediateLifecycleChaincode ic = new IntermediateLifecycleChaincode(
                chaincodeName,
                chaincodeVersion,
                chaincodeLabel,
                chaincodeSourceLocation,
                chaincodePath,
                metadadataSource,
                chaincodeEndorsementPolicyPath,
                null);
            pkid = ic.install(intermediateOrg);
        }catch (Exception e){
           return cn.flkj.lucia1a4a1.intermediate.Utils.RespError(e.getMessage(), ":)");
        }
        return JSONObject.parseObject( "{ "+ "\"package_id\":"+"\""+ pkid+"\"}") ;
    }

    public JSONObject lifecycleChaincodeApproveformyorg( String chaincodeName,
                                                         String chaincodeVersion,
                                                         String packageid) {
        IntermediateLifecycleChaincode ic = new IntermediateLifecycleChaincode(chaincodeName,chaincodeVersion,packageid);
        try {
            ic.approveformyorg(intermediateOrg);
        }catch (Exception e){
            return cn.flkj.lucia1a4a1.intermediate.Utils.RespError(e.getMessage(), ":)");
        }
        return  cn.flkj.lucia1a4a1.intermediate.Utils.RespError("success", ":)");
    }

    public JSONObject lifecycleChaincodeCommit( String chaincodeName,
                                                String chaincodeVersion,
                                                String packageid)  {
        IntermediateLifecycleChaincode ic = new IntermediateLifecycleChaincode(chaincodeName,chaincodeVersion,packageid);
        try {
            // 向通道提交链码
            ic.commit(intermediateOrg);
        }catch (Exception e){
            return cn.flkj.lucia1a4a1.intermediate.Utils.RespError(e.getMessage(), ":)");
        }
        return  cn.flkj.lucia1a4a1.intermediate.Utils.RespError("success", ":)");
    }

    /**
     * lifecycle Chaincode Init
     */
    public JSONObject lifecycleChaincodeInit(String chaincodeName,
                                             String chaincodeVersion,
                                             String packageid,
                                             String initFunc,
  String...args ) {
        IntermediateLifecycleChaincode ic = new IntermediateLifecycleChaincode(chaincodeName,chaincodeVersion,packageid);
        try {
            // 手动执行chaincode init 函数, 后期加入初始指定的函数
            ic.initChaincode(intermediateOrg,initFunc,args);
        }catch (Exception e){
           return cn.flkj.lucia1a4a1.intermediate.Utils.RespError(e.getMessage(), ":)");
        }
        return  cn.flkj.lucia1a4a1.intermediate.Utils.RespError("success", ":)");
    }

    //-----------------------生命周期查询-----------------------生命周期查询-----------------------生命周期查询-----------------------

//    public JSONObject lifecycleQueryCommittedCC() {
//
//        intermediateOrg.getClient().newLifecycleCommitChaincodeDefinitionRequest()
//        return new JSONObject();
//    }

    //-----------------------执行链码-----------------------执行链码-----------------------执行链码-----------------------

    /**
     * 智能合约执行
     *
     * @param chaincodeName 智能合约名
     * @param fcn           方法名
     * @param args          参数数组
     */

    public JSONObject invoke(String chaincodeName, String fcn, String[] args) {
        try {
            User user = intermediateOrg.getUser(intermediateOrg.getUsername());
            return IntermediateLifecycleChaincode.invoke(
                    intermediateOrg.getClient(),
                    intermediateOrg.getChannel().get(),
                    user,
                    chaincodeName,
                    fcn,
                    args);
        } catch (InvalidArgumentException | ProposalException | IOException e) {
            return cn.flkj.lucia1a4a1.intermediate.Utils.RespError(e.getMessage(), ":)");
        }
    }


    /**
     * 智能合约查询
     *
     * @param chaincodeName
     * @param fcn
     * @param args
     * @return
     * @throws InvalidArgumentException
     * @throws ProposalException
     */
    public JSONObject query(String chaincodeName, String fcn, String[] args) {
        try {
            return IntermediateLifecycleChaincode.query(
                    intermediateOrg.getClient(),
                    intermediateOrg.getChannel().get(),
                    chaincodeName,
                    fcn,
                    args);
        } catch (InvalidArgumentException | ProposalException e) {
            return cn.flkj.lucia1a4a1.intermediate.Utils.RespError(e.getMessage(), ":)");
        }
    }

    //-----------------------关于通道-----------------------关于通道-----------------------关于通道-----------------------

    public JSONObject queryBlockByNumber(long blockNumber) {
        try {
            return intermediateOrg.getChannel().queryBlockByNumber(intermediateOrg.getClient(), blockNumber);
        } catch (ProposalException | IOException | InvalidArgumentException e) {
            return cn.flkj.lucia1a4a1.intermediate.Utils.RespError(e.getMessage(), ":)");
        }
    }

    public JSONObject queryBlockByHash(String hash) {
        try {
            return intermediateOrg.getChannel().queryBlockByHash(
                    // 获取的区块Hash信息是被16进制编码后的hash，需要Hex decode -> byte[]
                    cn.flkj.lucia1a4a1.intermediate.Utils.hexStr2Byte(hash),
                    intermediateOrg.getClient());
        } catch (ProposalException | IOException | InvalidArgumentException e) {
            return cn.flkj.lucia1a4a1.intermediate.Utils.RespError(e.getMessage(), ":)");
        }
    }

    public JSONObject queryBlockByTransactionID(String txid) {
        try {
            return intermediateOrg.getChannel().queryBlockByTransactionID(txid, intermediateOrg.getClient());
        } catch (ProposalException | IOException | InvalidArgumentException e) {
            return cn.flkj.lucia1a4a1.intermediate.Utils.RespError(e.getMessage(), ":)");
        }
    }

    public JSONObject getBlockchainInfo() {
        try {
            return intermediateOrg.getChannel().getBlockchainInfo();
        } catch (ProposalException | InvalidArgumentException e) {
            return cn.flkj.lucia1a4a1.intermediate.Utils.RespError(e.getMessage(), ":)");
        }
    }

    public JSONObject queryInstantiated() {
        try {
            JSONObject json = new JSONObject();
            for (Peer peer : intermediateOrg.getChannel().get().getPeers()){
                json.put(peer.getName(),intermediateOrg.getChannel().queryInstantiated(peer));
            }
            return json;
        } catch (ProposalException | InvalidArgumentException e) {
            return cn.flkj.lucia1a4a1.intermediate.Utils.RespError(e.getMessage(), ":)");
        }
    }


}
